/**
 * @fileOverview The "menu" plugin.
 */
VED.plugins.add( 'menu', {
   requires: 'floatpanel',

   beforeInit: function( editor ) {
      var groups = editor.config.menu_groups.split( ',' ),
         groupsOrder = editor._.menuGroups = {},
         menuItems = editor._.menuItems = {};

      for ( var i = 0; i < groups.length; i++ )
         groupsOrder[ groups[ i ] ] = i + 1;

      editor.addMenuGroup = function( name, order ) {
         groupsOrder[ name ] = order || 100;
      };

      editor.addMenuItem = function( name, definition ) {
         if ( groupsOrder[ definition.group ] )
            menuItems[ name ] = new VED.menuItem( this, name, definition );
      };

      editor.addMenuItems = function( definitions ) {
         for ( var itemName in definitions ) {
            this.addMenuItem( itemName, definitions[ itemName ] );
         }
      };

      editor.getMenuItem = function( name ) {
         return menuItems[ name ];
      };

      editor.removeMenuItem = function( name ) {
         delete menuItems[ name ];
      };
   }
});

(function() {
   var menuItemSource = '<span class="ved_menuitem">' +
      '<a id="{id}"' +
      ' class="ved_menubutton ved_menubutton__{name} ved_menubutton_{state} {cls}" href="{href}"' +
      ' title="{title}"' +
      ' tabindex="-1"' +
      '_ved_focus=1' +
      ' hidefocus="true"' +
      ' role="menuitem"' +
      ' aria-haspopup="{hasPopup}"' +
      ' aria-disabled="{disabled}"';

   // Some browsers don't cancel key events in the keydown but in the
   // keypress.
   // TODO: Check if really needed for Gecko+Mac.
   if ( VED.env.opera || ( VED.env.gecko && VED.env.mac ) )
      menuItemSource += ' onkeypress="return false;"';

   // With Firefox, we need to force the button to redraw, otherwise it
   // will remain in the focus state.
   if ( VED.env.gecko )
      menuItemSource += ' onblur="this.style.cssText = this.style.cssText;"';

   // #188
   menuItemSource += ' onmouseover="VED.tools.callFunction({hoverFn},{index});"' +
         ' onmouseout="VED.tools.callFunction({moveOutFn},{index});" ' +
         ( VED.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) +
            '="VED.tools.callFunction({clickFn},{index}); return false;"' +
         '>';

   menuItemSource +=
            '<span class="ved_menubutton_inner">' +
               '<span class="ved_menubutton_icon">' +
                  '<span class="ved_button_icon ved_button__{iconName}_icon" style="{iconStyle}"></span>' +
               '</span>' +
               '<span class="ved_menubutton_label">' +
                  '{label}' +
               '</span>' +
               '{arrowHtml}' +
            '</span>' +
         '</a></span>';

   var menuArrowSource = '<span class="ved_menuarrow">' +
            '<span>{label}</span>' +
         '</span>';

   var menuItemTpl = VED.addTemplate( 'menuItem', menuItemSource ),
      menuArrowTpl = VED.addTemplate( 'menuArrow', menuArrowSource );

   /**
    * @class
    */
   VED.menu = new Class({
      initialize: function( editor, definition ) {
         this._ = {};
         definition = this._.definition = definition || {};
         this.id = VED.tools.getNextId();

         this.editor = editor;
         this.items = [];
         this._.listeners = [];

         this._.level = definition.level || 1;

         var panelDefinition = VED.tools.extend( {}, definition.panel, {
            css: [ VED.skin.getPath( 'editor' ) ], // ???????????????
            level: this._.level - 1,
            block: {}
         });

         var attrs = panelDefinition.block.attributes = ( panelDefinition.attributes || {} );
         // Provide default role of 'menu'.
         !attrs.role && ( attrs.role = 'menu' );
         this._.panelDefinition = panelDefinition;

         this._.onShow = function() {
            var selection = this.editor.getSelection(),
               start = selection && selection.getStartElement(),
               path = this.editor.elementPath(),
               listeners = this._.listeners;

            this.removeAll();
            // Call all listeners, filling the list of items to be displayed.
            for ( var i = 0; i < listeners.length; i++ ) {
               var listenerItems = listeners[ i ]( start, selection, path );

               if ( listenerItems ) {
                  for ( var itemName in listenerItems ) {
                     var item = this.editor.getMenuItem( itemName );

                     if ( item && ( !item.command || this.editor.getCommand( item.command ).state ) ) {
                        item.state = listenerItems[ itemName ];
                        this.add( item );
                     }
                  }
               }
            }
         }.bind(this);

         this._.onClick = function( item ) {
            this.hide();

            if ( item.onClick )
               item.onClick();
            else if ( item.command )
               this.editor.execCommand( item.command );
         }.bind(this);

         this._.onEscape = function( keystroke ) {
            var parentMenu = this.parentMenu;
            // 1. If it's sub-menu, close it, with focus restored on this.
            // 2. In case of a top-menu, close it, with focus returned to page.
            if ( parentMenu )
               parentMenu._.panel.hideChild( 1 );
            else if ( keystroke == 27 )
               this.hide( 1 );

            return false;
         }.bind(this);

         this._.onHide = function() {
            this.onHide && this.onHide();
         }.bind(this);

         this._.showSubMenu = function( index ) {
            var menu = this._.subMenu,
               item = this.items[ index ],
               subItemDefs = item.getItems && item.getItems();

            // If this item has no subitems, we just hide the submenu, if
            // available, and return back.
            if ( !subItemDefs ) {
               // Hide sub menu with focus returned.
               this._.panel.hideChild( 1 );
               return;
            }

            // Create the submenu, if not available, or clean the existing
            // one.
            if ( menu )
               menu.removeAll();
            else {
               menu = this._.subMenu = new VED.menu( this.editor, VED.tools.extend( {}, this._.definition, { level: this._.level + 1 }, true ) );
               menu.parentMenu = this;
               menu._.onClick = VED.tools.bind( this._.onClick, this );
            }

            // Add all submenu items to the menu.
            for ( var subItemName in subItemDefs ) {
               var subItem = this.editor.getMenuItem( subItemName );
               if ( subItem ) {
                  subItem.state = subItemDefs[ subItemName ];
                  menu.add( subItem );
               }
            }

            // Get the element representing the current item.
            var element = this._.panel.getBlock( this.id ).element.getDocument().getById( this.id + String( index ) );

            // Show the submenu.
            // This timeout is needed to give time for the sub-menu get
            // focus when JAWS is running. (#9844)
            setTimeout( function() {
               menu.show( element, 2 );
            },0);
         }.bind(this);

      },

      add: function( item ) {
         // Later we may sort the items, but Array#sort is not stable in
         // some browsers, here we're forcing the original sequence with
         // 'order' attribute if it hasn't been assigned. (#3868)
         if ( !item.order )
            item.order = this.items.length;

         this.items.push( item );
      },

      removeAll: function() {
         this.items = [];
      },

      show: function( offsetParent, corner, offsetX, offsetY ) {
         // Not for sub menu.
         if ( !this.parentMenu ) {
            this._.onShow();
            // Don't menu with zero items.
            if ( !this.items.length )
               return;
         }

         corner = corner || ( this.editor.lang.dir == 'rtl' ? 2 : 1 );

         var items = this.items,
            editor = this.editor,
            panel = this._.panel,
            element = this._.element;

         // Create the floating panel for this menu.
         if ( !panel ) {
            panel = this._.panel = new VED.ui.floatPanel( this.editor, VED.document.getBody(), this._.panelDefinition, this._.level );

            panel.onEscape = VED.tools.bind( function( keystroke ) {
               if ( this._.onEscape( keystroke ) === false )
                  return false;
            }, this );

            panel.onShow = function() {
               // Menu need CSS resets, compensate class name.
               var holder = panel._.panel.getHolderElement();
               holder.getParent().addClass( 'ved ved_reset_all' );
            };

            panel.onHide = VED.tools.bind( function() {
               this._.onHide && this._.onHide();
            }, this );

            // Create an autosize block inside the panel.
            var block = panel.addBlock( this.id, this._.panelDefinition.block );
            block.autoSize = true;

            var keys = block.keys;
            keys[ 40 ] = 'next'; // ARROW-DOWN
            keys[ 9 ] = 'next'; // TAB
            keys[ 38 ] = 'prev'; // ARROW-UP
            keys[ VED.SHIFT + 9 ] = 'prev'; // SHIFT + TAB
            keys[ ( editor.lang.dir == 'rtl' ? 37 : 39 ) ] = VED.env.ie ? 'mouseup' : 'click'; // ARROW-RIGHT/ARROW-LEFT(rtl)
            keys[ 32 ] = VED.env.ie ? 'mouseup' : 'click'; // SPACE
            VED.env.ie && ( keys[ 13 ] = 'mouseup' ); // Manage ENTER, since onclick is blocked in IE (#8041).

            element = this._.element = block.element;

            var elementDoc = element.getDocument();
            elementDoc.getBody().setStyle( 'overflow', 'hidden' );
            elementDoc.getElementsByTag( 'html' ).getItem( 0 ).setStyle( 'overflow', 'hidden' );

            this._.itemOverFn = VED.tools.addFunction( function( index ) {
               clearTimeout( this._.showSubTimeout );
               this._.showSubTimeout = VED.tools.setTimeout( this._.showSubMenu, editor.config.menu_subMenuDelay || 400, this, [ index ] );
            }, this );

            this._.itemOutFn = VED.tools.addFunction( function( index ) {
               clearTimeout( this._.showSubTimeout );
            }, this );

            this._.itemClickFn = VED.tools.addFunction( function( index ) {
               var item = this.items[ index ];

               if ( item.state == VED.TRISTATE_DISABLED ) {
                  this.hide( 1 );
                  return;
               }

               if ( item.getItems )
                  this._.showSubMenu( index );
               else
                  this._.onClick( item );
            }, this );
         }

         // Put the items in the right order.
         sortItems( items );

         // Apply the editor mixed direction status to menu.
         var path = editor.elementPath(),
            mixedDirCls = ( path && path.direction() != editor.lang.dir ) ? ' ved_mixed_dir_content' : '';

         // Build the HTML that composes the menu and its items.
         var output = [ '<div class="ved_menu' + mixedDirCls + '" role="presentation">' ];

         var length = items.length,
            lastGroup = length && items[ 0 ].group;

         for ( var i = 0; i < length; i++ ) {
            var item = items[ i ];
            if ( lastGroup != item.group ) {
               output.push( '<div class="ved_menuseparator" role="separator"></div>' );
               lastGroup = item.group;
            }

            item.render( this, i, output );
         }

         output.push( '</div>' );

         // Inject the HTML inside the panel.
         element.setHtml( output.join( '' ) );

         VED.ui.fire( 'ready', this );

         // Show the panel.
         if ( this.parentMenu )
            this.parentMenu._.panel.showAsChild( panel, this.id, offsetParent, corner, offsetX, offsetY );
         else
            panel.showBlock( this.id, offsetParent, corner, offsetX, offsetY );

         editor.fire( 'menuShow', [ panel ] );
      },

      addListener: function( listenerFn ) {
         this._.listeners.push( listenerFn );
      },

      hide: function( returnFocus ) {
         this._.onHide && this._.onHide();
         this._.panel && this._.panel.hide( returnFocus );
      }
   });

   function sortItems( items ) {
      items.sort( function( itemA, itemB ) {
         if ( itemA.group < itemB.group )
            return -1;
         else if ( itemA.group > itemB.group )
            return 1;

         return itemA.order < itemB.order ? -1 : itemA.order > itemB.order ? 1 : 0;
      });
   }

   /**
    * @class
    */
   VED.menuItem = new Class({
      initialize: function( editor, name, definition ) {
         VED.tools.extend( this, definition,
         // Defaults
         {
            order: 0,
            className: 'ved_menubutton__' + name
         });

         // Transform the group name into its order number.
         this.group = editor._.menuGroups[ this.group ];

         this.editor = editor;
         this.name = name;
      },

      render: function( menu, index, output ) {
         var id = menu.id + String( index ),
            state = ( typeof this.state == 'undefined' ) ? VED.TRISTATE_OFF : this.state;

         var stateName = state == VED.TRISTATE_ON ? 'on' : state == VED.TRISTATE_DISABLED ? 'disabled' : 'off';

         var hasSubMenu = this.getItems;
         // ltr: BLACK LEFT-POINTING POINTER
         // rtl: BLACK RIGHT-POINTING POINTER
         var arrowLabel = '&#' + ( this.editor.lang.dir == 'rtl' ? '9668' : '9658' ) + ';';

         var iconName = this.name;
         if ( this.icon && !( /\./ ).test( this.icon ) )
            iconName = this.icon;

         var params = {
            id: id,
            name: this.name,
            iconName: iconName,
            label: this.label,
            cls: this.className || '',
            state: stateName,
            hasPopup: hasSubMenu ? 'true' : 'false',
            disabled: state == VED.TRISTATE_DISABLED,
            title: this.label,
            href: 'javascript:void(\'' + ( this.label || '' ).replace( "'" + '' ) + '\')',
            hoverFn: menu._.itemOverFn,
            moveOutFn: menu._.itemOutFn,
            clickFn: menu._.itemClickFn,
            index: index,
            iconStyle: VED.skin.getIconStyle( iconName, ( this.editor.lang.dir == 'rtl' ), iconName == this.icon ? null : this.icon, this.iconOffset ),
            arrowHtml: hasSubMenu ? menuArrowTpl.output({ label: arrowLabel } ) : ''
         };

         menuItemTpl.output( params, output );
      }
   });

})();


VED.config.menu_groups = 'clipboard,' +
   'form,' +
   'tablecell,tablecellproperties,tablerow,tablecolumn,table,' +
   'anchor,link,image,flash,' +
   'checkbox,radio,textfield,hiddenfield,imagebutton,button,select,textarea,div';






